package com.xnx3.kefu.core.util;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;

import com.aliyun.openservices.log.common.LogItem;
import com.aliyun.openservices.log.exception.LogException;
import com.xnx3.elasticsearch.ElasticSearchUtil;
import com.xnx3.j2ee.Global;
import com.xnx3.j2ee.util.ActionLogUtil;
import com.xnx3.j2ee.util.ConsoleUtil;
import com.xnx3.j2ee.util.SystemUtil;
import com.xnx3.j2ee.util.actionLog.ElasticSearchMode;
import com.xnx3.j2ee.vo.ActionLogListVO;
import com.xnx3.net.AliyunLogUtil;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import com.xnx3.kefu.core.vo.MessageListVO;
import com.xnx3.kefu.core.vo.MessageReceiveVO;

/**
 * 消息存储相关。这里直接将消息推送到阿里云日志服务
 * @author 管雷鸣
 */
@Component(value="KefuCoreMessageStorageUtil")
public class MessageStorageUtil extends com.xnx3.j2ee.util.ActionLogUtil{
	public static String logstore = "message";	//专门存储message聊天记录的日志库名字
	public static AliyunLogUtil aliyunLogUtil;
	public static ElasticSearchUtil esUtil;
	
	static{
		new Thread(new Runnable() {
			@Override
			public void run() {
				while(Global.system.size() < 1){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				//当数据库加载完后，再初始化
				//判断是否使用日志服务进行日志记录，条件便是 accessKeyId 是否为空。若为空，则不使用
				String use = SystemUtil.get("ALIYUN_SLS_USE");
				if(use != null && use.equals("1")){
					//使用日志服务
					
					String keyId = SystemUtil.get("ALIYUN_ACCESSKEYID");
					String keySecret = SystemUtil.get("ALIYUN_ACCESSKEYSECRET");
					String endpoint = SystemUtil.get("ALIYUN_SLS_ENDPOINT");
					String project = SystemUtil.get("ALIYUN_SLS_PROJECT");
					
					//最大超时时间
					int log_cache_max_time = SystemUtil.getInt("ALIYUN_SLS_CACHE_MAX_TIME");
					if(log_cache_max_time == 0){
						log_cache_max_time = 120;
					}
					//最大条数
					int log_cache_max_number = SystemUtil.getInt("ALIYUN_SLS_CACHE_MAX_NUMBER");
					if(log_cache_max_number == 0){
						log_cache_max_number = 100;
					}
					
					
					if(keyId.length() > 10){
						aliyunLogUtil = new AliyunLogUtil(endpoint,  keyId, keySecret, project, logstore);
						aliyunLogUtil.setCacheAutoSubmit(0, 0);
						//ConsoleUtil.info("开启kefu日志服务进行消息的持久化存储");
					}else{
						//此处可能是还没执行install安装
					}
				}
				
				
				//判断当前使用的是Elasticsearch，还是阿里云日志服务。（阿里云日志服务已过时，不再使用。保留仅仅只是向前兼容）
				if(!ActionLogUtil.isUse()) {
					//未启用两个任何一个，报错
					ConsoleUtil.log("注意，你还没配置日志存储服务，将不会存储任何历史消息！！");
					return;
				}
				//获取当前日志是配置的哪种
				String logMode = ActionLogUtil.actionLogInterface.getClass().getSimpleName();
				if(logMode.equals("AliyunSLSMode")) {
					ConsoleUtil.info("采用阿里云日志服务存储日志消息。");
					//使用的阿里云的日志服务
					if(aliyunLogUtil == null){
						//未使用持久化消息记录
						return;
					}
				}else if(logMode.equals("ElasticSearchMode")) {
					ConsoleUtil.info("采用Elasticsearch存储日志消息。");
					esUtil = ElasticSearchMode.es;
					
					//判断index是否创建了，如果没创建，进行创建
					if(!esUtil.existIndex(logstore)) {
						ConsoleUtil.info("当前第一次使用，自动创建 ElasticSearch 的 index : "+logstore);
						try {
							esUtil.createIndex(logstore);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}).start();
	}
	
	/**
	 * 推送一条消息进来
	 * @param msg socket 接收到的消息，当socket接收到消息后，会立即推送过来
	 */
	public static void push(MessageReceiveVO msg){
		if(esUtil != null) {
			//使用的elasticsearch
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("type", msg.getType());
			map.put("extend", msg.getExtend() == null? "[]":msg.getExtend().toString());
			map.put("receiveId", msg.getReceiveId());
			map.put("sendId", msg.getSendId());
			map.put("text", msg.getText());
			map.put("time", msg.getTime());
			esUtil.cache(map, logstore);
			esUtil.cacheSubmit(logstore);
			return;
		}
		
		if(aliyunLogUtil != null) {
			//使用的阿里云日志服务
			LogItem logItem = new LogItem((int) (new Date().getTime() / 1000));
			logItem.PushBack("type", msg.getType());
			logItem.PushBack("extend", msg.getExtend() == null? "[]":msg.getExtend().toString());
			logItem.PushBack("receiveId", msg.getReceiveId());
			logItem.PushBack("sendId", msg.getSendId());
			logItem.PushBack("text", msg.getText());
			logItem.PushBack("time", msg.getTime()+"");
			
			try {
				aliyunLogUtil.cacheLog(logItem);
				//aliyunLogUtil.cacheCommit();
			} catch (LogException e) {
				e.printStackTrace();
			}
			return;
		}
	}
	
	
	/**
	 * 查看我跟某人的历史聊天记录
	 * @param myChatid 当前我的chatid
	 * @param otherChatId 跟我聊天对方的chatid
	 * @param time 13位时间戳，要获取这个时间之前的记录
	 * @param number 要获取多少条记录，取值10~200之间，不传默认是100条
	 * @param type 类型，取数据的类型，可传入 before、after，  before:向前，也就是取<time的记录，after:向后,也就是取>time的记录 。默认不传则是before
	 */
	public static MessageListVO chatLog(String myChatid, String otherChatId, long time, int number, String type, HttpServletRequest request){
		MessageListVO vo = new MessageListVO();
		if(myChatid == null){
			vo.setBaseVO(MessageListVO.FAILURE, "没有发现你这个用户");
			return vo;
		}
		
		//参数校验
		if(number < 10){
			number = 10;
		}
		if(number > 200){
			number = 200;
		}
		if(otherChatId == null || otherChatId.length() == 0){
			vo.setBaseVO(MessageListVO.FAILURE, "请传入对方的chatid");
			return vo;
		}
		if(type == null || type.length() == 0){
			type = "before";
		}
		
		
		if(!ActionLogUtil.isUse()){
			vo.setBaseVO(MessageListVO.FAILURE, "未开启聊天持久化内容记录");
			return vo;
		}
		if(!(type.equalsIgnoreCase("before") || type.equalsIgnoreCase("after"))){
			vo.setBaseVO(MessageListVO.FAILURE, "type传入错误！请传入after、before");
			return vo;
		}
		
		//得到当前页面的列表数据
		String query = "((sendId="+myChatid+" AND receiveId="+otherChatId+") OR (sendId="+otherChatId+" AND receiveId="+myChatid+")) ";
		
		if(MessageStorageUtil.esUtil != null){
			//使用的es
		    
		    //获取查询结果的数据 
	    	SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    		QueryBuilder queryBuilder = QueryBuilders.queryStringQuery(query);
    		
    		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    		boolQueryBuilder.must(queryBuilder);
    		
    		if(type.equalsIgnoreCase("before")){
    			boolQueryBuilder.must(QueryBuilders.rangeQuery("time").lte(time-1));
			}else if(type.equalsIgnoreCase("after")){
				boolQueryBuilder.must(QueryBuilders.rangeQuery("time").gte(time+1));
			}
    		searchSourceBuilder.query(boolQueryBuilder);
    		searchSourceBuilder.sort(SortBuilders.fieldSort("time").order(SortOrder.DESC));
    		SearchResponse response = MessageStorageUtil.esUtil.search(MessageStorageUtil.logstore, searchSourceBuilder, 0, number);
			
    		JSONArray array = new JSONArray();
	        if(response.status().getStatus() == 200){
	        	SearchHit shs[] = response.getHits().getHits();
	        	for (int i = 0; i < shs.length; i++) {
	        		Map<String, Object> map = shs[i].getSourceAsMap();
	        		//map.put("esid", shs[i].getId());
	        		array.add(JSONObject.fromObject(map));
				}
	        }else{
	        	//异常
	        	System.out.println("异常");
	        }
			vo.setList(array);
		}else if(MessageStorageUtil.aliyunLogUtil != null){
			if(type.equalsIgnoreCase("before")){
				query = query + "AND time < "+time;
			}else if(type.equalsIgnoreCase("after")){
				query = query + "AND time > "+time;
			}
			

			ActionLogListVO listVO = ActionLogUtil.list(MessageStorageUtil.logstore, query, number, request);
			if(listVO.getResult() - ActionLogListVO.FAILURE == 0){
				vo.setBaseVO(MessageListVO.FAILURE, listVO.getInfo());
				return vo;
			}
			vo.setList(listVO.getJsonArray());
		}
		
		vo.setEndTime(time);
		vo.setNumber(vo.getList().size());
		if(vo.getList().size() > 0){
			//如果有数据，那么取最后一条的时间
			JSONObject lastJson = vo.getList().getJSONObject(vo.getNumber() -1 );
			vo.setStartTime(getLong(lastJson, "time"));
		}
		
		return vo;
	}
	
	/**
	 * 取json的long类型value
	 */
	private static long getLong(JSONObject json, String key){
		if(json.get(key) != null){
			return json.getLong(key);
		}
		return 0;
	}
}
